/*-
 * Copyright 2012 Guram Dukashvili
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
//---------------------------------------------------------------------------
#include "sys.h"
#include "list.h"
//---------------------------------------------------------------------------
struct list * list_new(void)
{
  struct list * lst = salloc(sizeof(struct list),NULL);
  if( lst != NULL )
    list_init(lst);
  return lst;
}
//---------------------------------------------------------------------------
void list_init(struct list * lst)
{
  lst->head = lst->tail = NULL;
  lst->count = lst->node = 0;
}
//---------------------------------------------------------------------------
void list_set_node(struct list * lst,const void * data,const struct list_node * node)
{
  lst->node = (uintptr_t) node - (uintptr_t) data;
}
//---------------------------------------------------------------------------
void list_delete(struct list * lst)
{
#if COMPILE_RUNTIME_CHECKS
  if( lst->count != 0 ){
    fprintf(stderr,"undefined behavior in %s, line %d\n",__FILE__,__LINE__);
    abort();
  }
#endif
  sfree(lst);
}
//---------------------------------------------------------------------------
void list_destroy(struct list * lst)
{
#if COMPILE_RUNTIME_CHECKS
  if( lst->count != 0 ){
    fprintf(stderr,"undefined behavior in %s, line %d\n",__FILE__,__LINE__);
    abort();
  }
#endif
  lst->head = lst->tail = NULL;
  lst->count = lst->node = 0;
}
//---------------------------------------------------------------------------
static __inline__ void insert(
  struct list * lst,
  void * data,
  struct list_node * prev,
  struct list_node * next)
{
  struct list_node * node = list_data2node(lst,data);
  node->prev = prev;
  node->next = next;
  if( prev == NULL ) lst->head = node; else prev->next = node;
  if( next == NULL ) lst->tail = node; else next->prev = node;
  lst->count++;
}
//-----------------------------------------------------------------------------
void list_insert_head(struct list * lst,void * data)
{
  insert(lst,data,NULL,lst->head);
}
//-----------------------------------------------------------------------------
void list_insert_tail(struct list * lst,void * data)
{
  insert(lst,data,lst->tail,NULL);
}
//-----------------------------------------------------------------------------
void list_insert_before(struct list * lst,void * before_data,void * data)
{
  struct list_node * before_node = list_data2node(lst,before_data);
  insert(lst,data,before_node->next,before_node);
}
//-----------------------------------------------------------------------------
void list_insert_after(struct list * lst,void * after_data,void * data)
{
  struct list_node * after_node = list_data2node(lst,after_data);
  insert(lst,data,after_node,after_node->next);
}
//-----------------------------------------------------------------------------
void list_remove(struct list * lst,void * data)
{
  struct list_node * node = list_data2node(lst,data);
  if( node->prev != NULL ){
    node->prev->next = node->next;
  }
  else {
    lst->head = node->next;
  }
  if( node->next != NULL ){
    node->next->prev = node->prev;
  }
  else {
    lst->tail = node->prev;
  }
#if COMPILE_RUNTIME_CHECKS
  memset(node,0xFE,sizeof(*node));
#endif
  lst->count--;
}
//-----------------------------------------------------------------------------
